package com.unlcn.ils.kas.service.order.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.mysql.cj.xdevapi.Collection;
import com.unlcn.ils.kas.dao.model.order.Customer;
import com.unlcn.ils.kas.dao.model.order.OrderOtd;
import com.unlcn.ils.kas.dao.model.order.OrderOtdDetail;
import com.unlcn.ils.kas.service.map.BaiDuMap.util.BaiDuMapGeocodeUtil;
import com.unlcn.ils.kas.service.map.BaiDuMap.util.BaiDuMapRouteUtil;
import com.unlcn.ils.kas.service.order.CustomerService;
import com.unlcn.ils.kas.service.order.ImportService;
import com.unlcn.ils.kas.service.order.OrderOtdDetailService;
import com.unlcn.ils.kas.service.order.OrderOtdService;
import com.unlcn.ils.kas.service.util.DateUtils;
import com.unlcn.ils.kas.service.util.enums.order.OrderDetailDeleteFlagEnum;
import com.unlcn.ils.kas.service.util.enums.order.OrderDetailIsmanualEnum;
import com.unlcn.ils.kas.service.util.enums.order.OrderWayEnum;
import com.unlcn.ils.kas.service.util.enums.order.TransportTypeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.unlcn.ils.kas.service.map.BaiDuMap.util.BaiDuMapGeocodeUtil.addressToGPS;

/**
 * 导入订单 service 实现
 *
 * @author 罗必量
 */
@Service
public class ImportServiceImpl implements ImportService {

    private static final Logger LOGGER = LoggerFactory.getLogger(ImportServiceImpl.class);

    final static int MILLISECOND_OF_DAY = 86400000;
    final static String STRING_DATE_FORMAT = "string-date-format";
    final static String STRING_DATE_FORMAT1 = "string-date-format1";
    final static String NUMBER_DAYS_FORMAT_WITH_CLOCK = "number-days-format-with-clock";
    final static String NUMBER_DAYS_FORMAT_ONLY_DATE = "number-days-format-only-date";
    final static String NUMBER_MILLISECOND_FORMAT = "number-millisecond-format";
    final static String NOT_DATE_FORMAT = "非日期时间单元";

    @Autowired
    private OrderOtdService orderOtdService;

    @Autowired
    private OrderOtdDetailService orderOtdDetailService;

    @Autowired
    private CustomerService customerService;

    @Override
    public Map<String, String> importOrder(String data) {

        String result;

        JSONObject jsonObject = JSONObject.parseObject(data);
        JSONArray arrayHeader = JSONObject.parseArray(jsonObject.getString("header"));
        arrayHeader.add("导入结果");
        arrayHeader.add("执行信息");

        JSONArray arrayRows = JSONObject.parseArray(jsonObject.getString("rows"));

        int rows_successed = 0, rows_err = 0;

        boolean transport_type_is_legal = true;

        List<JSONObject> saveList = new ArrayList<>();
        for (int i = 0; i < arrayRows.size(); i++) {
            try {
                OrderOtd orderOtd = new OrderOtd();

                // 如果为空则不进行保存
                if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("中联订单号"))) {
                    break;
                }

                if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("客户订单号"))) {
                    // continue;
                }

                if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("客户名称"))) {
                    break;
                }

                // 中联订单号
                orderOtd.setSysOrderNo(arrayRows.getJSONObject(i).getString("中联订单号").trim());
                // 客户订单号
                orderOtd.setCustomerOrderNo(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("客户订单号")) ? "无"
                        : arrayRows.getJSONObject(i).getString("客户订单号").trim());
                // 客户名称
                orderOtd.setCustomerName(arrayRows.getJSONObject(i).getString("客户名称").trim());

                // 订单日期
                if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("订单日期"))
                        || arrayRows.getJSONObject(i).getString("订单日期").equals("-")) {
                    orderOtd.setOrderDate(null);
                } else {
                    orderOtd.setOrderDate(
                            formatCellValue2Date(arrayRows.getJSONObject(i).getString("订单日期").trim(), "订单日期"));
                }
                // 车架号
                orderOtd.setVin(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("车架号")) ? null
                        : arrayRows.getJSONObject(i).getString("车架号").trim());
                // 车型代码
                orderOtd.setStyleCode(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("车型代码")) ? null
                        : arrayRows.getJSONObject(i).getString("车型代码").trim());
                // 车型名称
                orderOtd.setStyleName(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("车型名称")) ? null
                        : arrayRows.getJSONObject(i).getString("车型名称").trim());
                // 经销商名称
                orderOtd.setDealerName(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("经销商名称")) ? null
                        : arrayRows.getJSONObject(i).getString("经销商名称").trim());
                // 发车省
                orderOtd.setoProvince(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("发车省")) ? null
                        : arrayRows.getJSONObject(i).getString("发车省").trim());
                // 发车市
                orderOtd.setoCity(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("发车市")) ? null
                        : arrayRows.getJSONObject(i).getString("发车市").trim());
                // 发车地址
                orderOtd.setoAddress(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("发车地址")) ? null
                        : arrayRows.getJSONObject(i).getString("发车地址").trim());
                // 收车省
                orderOtd.setdProvince(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("收车省")) ? null
                        : arrayRows.getJSONObject(i).getString("收车省").trim());
                // 收车市
                orderOtd.setdCity(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("收车市")) ? null
                        : arrayRows.getJSONObject(i).getString("收车市").trim());
                // 收车地址
                orderOtd.setdAddress(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("收车地址")) ? null
                        : arrayRows.getJSONObject(i).getString("收车地址").trim());
                // 运输距离
                orderOtd.setDistance(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("运输距离")) ? null
                        : Float.valueOf(arrayRows.getJSONObject(i).getString("运输距离").trim()));
                // 订单状态
                orderOtd.setOrderStatus(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("订单状态")) ? null
                        : arrayRows.getJSONObject(i).getString("订单状态").trim());
                // 运输方式
                orderOtd.setTransportType(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("运输方式")) ? "-"
                        : arrayRows.getJSONObject(i).getString("运输方式").trim());
                // 接单时间
                if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("接单时间"))
                        || arrayRows.getJSONObject(i).getString("接单时间").equals("-")) {
                    orderOtd.setOrderCreateTime(null);
                } else {
                    orderOtd.setOrderCreateTime(
                            formatCellValue2Date(arrayRows.getJSONObject(i).getString("接单时间").trim(), "接单时间"));
                }
                // 提车时间
                if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("提车时间"))
                        || arrayRows.getJSONObject(i).getString("提车时间").equals("-")) {
                    orderOtd.setPickTime(null);
                } else {
                    orderOtd.setPickTime(
                            formatCellValue2Date(arrayRows.getJSONObject(i).getString("提车时间").trim(), "提车时间"));
                }
                // 打单时间
                if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("打单时间"))
                        || arrayRows.getJSONObject(i).getString("打单时间").equals("-")) {
                    orderOtd.setPrintOrderTime(null);
                } else {
                    orderOtd.setPrintOrderTime(
                            formatCellValue2Date(arrayRows.getJSONObject(i).getString("打单时间").trim(), "打单时间"));
                }
                // 入中联库时间
                if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("入中联库时间"))
                        || arrayRows.getJSONObject(i).getString("入中联库时间").equals("-")) {
                    orderOtd.setInboundTime(null);
                } else {
                    orderOtd.setInboundTime(
                            formatCellValue2Date(arrayRows.getJSONObject(i).getString("入中联库时间").trim(), "入中联库时间"));
                }
                // 安排运力时间
                if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("安排运力时间"))
                        || arrayRows.getJSONObject(i).getString("安排运力时间").equals("-")) {
                    orderOtd.setArrangeCapacityTime(null);
                } else {
                    orderOtd.setArrangeCapacityTime(
                            formatCellValue2Date(arrayRows.getJSONObject(i).getString("安排运力时间").trim(), "安排运力时间"));
                }
                // 出中联库时间
                if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("出中联库时间"))
                        || arrayRows.getJSONObject(i).getString("出中联库时间").equals("-")) {
                    orderOtd.setOutboundTime(null);
                } else {
                    orderOtd.setOutboundTime(
                            formatCellValue2Date(arrayRows.getJSONObject(i).getString("出中联库时间").trim(), "出中联库时间"));
                }
                // 入铁路库时间
                if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("入铁路库时间"))
                        || arrayRows.getJSONObject(i).getString("入铁路库时间").equals("-")) {
                    orderOtd.setEnterRailwayTime(null);
                } else {
                    orderOtd.setEnterRailwayTime(
                            formatCellValue2Date(arrayRows.getJSONObject(i).getString("入铁路库时间").trim(), "入铁路库时间"));
                }
                // 装车时间
                if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("装车时间"))
                        || arrayRows.getJSONObject(i).getString("装车时间").equals("-")) {
                    orderOtd.setLoadTime(null);
                } else {
                    orderOtd.setLoadTime(
                            formatCellValue2Date(arrayRows.getJSONObject(i).getString("装车时间").trim(), "装车时间"));
                }
                // 离昌时间
                if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("离昌时间"))
                        || arrayRows.getJSONObject(i).getString("离昌时间").equals("-")) {
                    orderOtd.setLeaveTime(null);
                } else {
                    orderOtd.setLeaveTime(
                            formatCellValue2Date(arrayRows.getJSONObject(i).getString("离昌时间").trim(), "离昌时间"));
                }
                // 承运车队名称
                orderOtd.setSupplier(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("承运车队名称")) ? null
                        : arrayRows.getJSONObject(i).getString("承运车队名称").trim());
                // 司机联系方式
                orderOtd.setDriverPhone(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("司机联系方式")) ? null
                        : arrayRows.getJSONObject(i).getString("司机联系方式").trim());
                // 手动司机联系方式
                orderOtd.setManualDriverPhone(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("司机联系方式")) ? null
                        : arrayRows.getJSONObject(i).getString("司机联系方式").trim());
                // 车牌号
                orderOtd.setLicensePlate(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("车牌号")) ? null
                        : arrayRows.getJSONObject(i).getString("车牌号").trim());
                // 送达时间
                if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("送达时间"))
                        || arrayRows.getJSONObject(i).getString("送达时间").equals("-")) {
                    orderOtd.setShiptoTime(null);
                    orderOtd.setManualShiptoTime(null);
                    // 预计送达时间
                    if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("预计送达时间"))
                            || arrayRows.getJSONObject(i).getString("预计送达时间").equals("-")) {
                        orderOtd.setPlanShiptoTime(null);
                    } else {
                        orderOtd.setPlanShiptoTime(
                                formatCellValue2Date(arrayRows.getJSONObject(i).getString("预计送达时间").trim(), "预计送达时间"));
                    }

                    // 最新在途位置
                    orderOtd.setNewestPosition(
                            StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("最新在途位置")) ? null
                                    : arrayRows.getJSONObject(i).getString("最新在途位置").trim());
                    // 最新在途时间
                    if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("最新在途时间"))
                            || arrayRows.getJSONObject(i).getString("最新在途时间").equals("-")) {
                        orderOtd.setNewestTime(null);
                    } else {
                        orderOtd.setNewestTime(
                                formatCellValue2Date(arrayRows.getJSONObject(i).getString("最新在途时间").trim(), "最新在途时间"));
                    }

                } else {
                    orderOtd.setShiptoTime(
                            formatCellValue2Date(arrayRows.getJSONObject(i).getString("送达时间").trim(), "送达时间"));
                    orderOtd.setManualShiptoTime(
                            formatCellValue2Date(arrayRows.getJSONObject(i).getString("送达时间").trim(), "送达时间"));
                    orderOtd.setPlanShiptoTime(
                            formatCellValue2Date(arrayRows.getJSONObject(i).getString("送达时间").trim(), "送达时间"));
                    // 有送达时间的话，那最新在途位置就是收车地址
                    orderOtd.setNewestTime(
                            formatCellValue2Date(arrayRows.getJSONObject(i).getString("送达时间").trim(), "送达时间"));
                    String newestPosition = (StringUtils.isEmpty(orderOtd.getdProvince()) ? ""
                            : orderOtd.getdProvince())
                            + (StringUtils.isEmpty(orderOtd.getdCity()) ? "" : orderOtd.getdCity())
                            + (StringUtils.isEmpty(orderOtd.getdAddress()) ? "" : orderOtd.getdAddress());
                    newestPosition = newestPosition.replaceAll("null", "");
                    orderOtd.setNewestPosition(newestPosition);

                }
                // 回单时间
                if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("回单时间"))
                        || arrayRows.getJSONObject(i).getString("回单时间").equals("-")) {
                    orderOtd.setReturnOrderTime(null);
                } else {
                    orderOtd.setReturnOrderTime(
                            formatCellValue2Date(arrayRows.getJSONObject(i).getString("回单时间").trim(), "回单时间"));
                }
                // 发运类型
                orderOtd.setShipmentType(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("发运类型")) ? null
                        : arrayRows.getJSONObject(i).getString("发运类型").trim());

                // 备注
                orderOtd.setRemark(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("备注")) ? null
                        : arrayRows.getJSONObject(i).getString("备注").trim());
                // 备注说明
                orderOtd.setRemarkDesc(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("备注说明")) ? null
                        : arrayRows.getJSONObject(i).getString("备注说明").trim());
                // 添加临牌号 2019-05-29 14:07:59
                orderOtd.setTempLicense(StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("临牌号")) ? null
                        : arrayRows.getJSONObject(i).getString("临牌号").trim());

                if (orderOtd.getDistance() == null || 0 == orderOtd.getDistance()) {
                    // 计算起运地到目的地运输距离
                    String startAddress = orderOtd.getoProvince() + orderOtd.getoCity() + orderOtd.getoAddress();
                    String endAddress = orderOtd.getdProvince() + orderOtd.getdCity() + orderOtd.getdAddress();
                    double routeDistance = BaiDuMapRouteUtil.getDistance(startAddress, endAddress) / 1000;
                    orderOtd.setDistance(Float.parseFloat(Double.toString(Math.ceil(routeDistance))));
                }

                // 查询客户编号
                EntityWrapper<Customer> entityCustom = new EntityWrapper<Customer>();
                entityCustom.eq("name", orderOtd.getCustomerName());
                List<Customer> customerList = customerService.selectList(entityCustom);
                if (!CollectionUtils.isEmpty(customerList)) {
                    orderOtd.setCustomerNo(customerList.get(0).getCode());
                } else {
                    throw new IllegalArgumentException("无效的客户名称");
                }

                // 判断订单状态
                if (orderOtd.getLeaveTime() == null) {
                    orderOtd.setOrderStatus("未离昌");
                }
                if (orderOtd.getLeaveTime() != null) {
                    orderOtd.setOrderStatus("在途");
                }
                if (orderOtd.getShiptoTime() != null) {
                    orderOtd.setOrderStatus("交付");
                }

                // 判断运输方式类型
                transport_type_is_legal = false;

                for (TransportTypeEnum tt : TransportTypeEnum.values()) {
                    if (orderOtd.getTransportType().equalsIgnoreCase(tt.getType())) {
                        orderOtd.setTransportTypeCode(tt.getCode());
                        transport_type_is_legal = true;
                    }
                }

                if (!transport_type_is_legal) {
                    throw new IllegalArgumentException("运输方式无效");
                }

                // 数据源
                orderOtd.setWay(OrderWayEnum.WAY_EXCEL.getCode());

                insertOrUpdateOtd(orderOtd);

                // 判断是否存在最新时间和最新位置，存在则插入一条明细
                if (isValidNewestLocate(orderOtd)) {
                    if (!isExistsSameTimeLocate(orderOtd)) {
                        OrderOtdDetail orderOtdDetail = calcOtdDetailFromNewestLocate(orderOtd);
                        if (!StringUtils.isEmpty(orderOtdDetail)) {
                            // 是否手动添加（是）
                            orderOtdDetail.setIsmanual(OrderDetailIsmanualEnum.YES.getCode());

                            orderOtdDetailService.insert(orderOtdDetail);

                            // 删除比手动维护的时间要晚，并且距离要远的数据
                            deleteConflictOtdDetail(orderOtdDetail);
                        }
                    }
                }

                arrayRows.getJSONObject(i).put("导入结果", "成功");
                arrayRows.getJSONObject(i).put("执行信息", "成功！");

                updateNewestPositionRelInfo(orderOtd.getSysOrderNo());
                rows_successed++;
            } catch (Exception e) {
                LOGGER.error("ImportServiceImpl.importOrder ERROR Message : {} ", e);

                arrayRows.getJSONObject(i).put("导入结果", "失败");
                arrayRows.getJSONObject(i).put("执行信息", e.getMessage());
                rows_err++;

                // 只反馈导入异常数据到前端
                JSONObject saveObject = (JSONObject) arrayRows.get(i);
                saveList.add(saveObject);
            }

        }

        result = JSONArray.toJSONString(saveList);

        Map<String, String> map = new HashMap<>();
        map.put("header", JSONArray.toJSONString(arrayHeader));
        map.put("rows", result);
        map.put("rows_err", rows_err + "");
        map.put("rows_successed", rows_successed + "");

        return map;
    }

    /**
     * 导入在途轨迹
     *
     * @param data
     */
    @Override
    @Transactional
    public Map<String, String> importOnway(String data) {
        String result;
        JSONObject jsonObject = JSONObject.parseObject(data);
        JSONArray arrayHeader = JSONObject.parseArray(jsonObject.getString("header"));
        JSONArray arrayRows = JSONObject.parseArray(jsonObject.getString("rows"));
        arrayHeader.add("导入结果");
        arrayHeader.add("执行信息");
        int rows_successed = 0;
        List<JSONObject> errRetList = new ArrayList<>();

        Map<String, JSONObject> checkLastDate = new HashMap<>();
        Map<String, JSONObject> needImportDNGrouped = new HashMap<>();
        // gpsMap保存需要使用百度地图api的地址 避免重复查询
        Map<String, Map<String, String>> addressMap = new HashMap<>();
        // 利用map不可重复原理 筛选出 时间最大 订单加入 MAP groupDn
        // 当整组订单 即相同的dn 都合格情况下才进行业务逻辑处理
        // 是否运达 为是的 订单加入 checkLastDate 当checkLastDate中相同dn 时间不同说明 是否运达 为是的 运抵时间小于其中一个
        for (int i = 0; i < arrayRows.size(); i++) {
            try {
                String dn = arrayRows.getJSONObject(i).getString("ＤＮ").trim();
                String isReach = arrayRows.getJSONObject(i).getString("是否运抵");
                // 去空格
                if (!StringUtils.isEmpty(isReach)) {
                    isReach = isReach.trim();
                }
                // 当前定位时间
                Date locationDate1 = formatCellValue2Date(arrayRows.getJSONObject(i).getString("定位时间").trim(), "定位时间");
                if (needImportDNGrouped.containsKey(dn)) {
                    // map中保存的定位时间
                    Date locationDate2 = formatCellValue2Date(needImportDNGrouped.get(dn).getString("定位时间").trim(),
                            "定位时间");
                    if (locationDate1.after(locationDate2)) {
                        needImportDNGrouped.put(dn, arrayRows.getJSONObject(i));
                    }
                } else {
                    needImportDNGrouped.put(dn, arrayRows.getJSONObject(i));
                }
                if (!StringUtils.isEmpty(isReach) && isReach.equals("是")) {
                    checkLastDate.put(dn, arrayRows.getJSONObject(i));
                }
            } catch (Exception e) {
                LOGGER.error("ImportServiceImpl.importOnway:", e);
                arrayRows.getJSONObject(i).put("导入结果", "失败");
                arrayRows.getJSONObject(i).put("执行信息", e.getMessage());
                errRetList.add((JSONObject) arrayRows.getJSONObject(i));
            }
        }

        // 再判断checkLastDate和groupDn 相同单号的时间是否相同
        // 并且判断checkLastDate中 定位位置 百度api解析是否成功
        // 在遍历集合的时候改变集合的size会导致错误

        // 如果某DN的运抵行定位时间不是该DN的最大定位时间,则为致命异常,该DN所有记录不导入
        List<String> fatalErrCanNotImportDNList = new ArrayList<String>();
        for (Map.Entry<String, JSONObject> entry : needImportDNGrouped.entrySet()) {
            if (checkLastDate.containsKey(entry.getKey())) {
                String errMsg = "";
                try {
                    Boolean flag = true;
                    Date date1 = formatCellValue2Date(entry.getValue().getString("定位时间").trim(), "定位时间");
                    Date date2 = formatCellValue2Date(checkLastDate.get(entry.getKey()).getString("定位时间").trim(),
                            "定位时间");
                    // 检测重复位置
                    Map<String, String> geoPoint = checkAddress(entry.getValue().getString("定位位置").trim(), addressMap);
                    if (null != geoPoint && !CollectionUtils.isEmpty(geoPoint)
                            && !StringUtils.isEmpty(geoPoint.get("lat"))) {
                        addressMap.put(entry.getValue().getString("定位位置").trim(), geoPoint);
                    }
                    if (date1.getTime() != date2.getTime()) {
                        errMsg += "此类单号是否运抵应为此订单,";
                        flag = false;
                    }
                    // 正常情况 addressToGPS百度api 返回size 为2的 map
                    if (StringUtils.isEmpty(geoPoint) || StringUtils.isEmpty(geoPoint.get("province"))) {
                        if (StringUtils.isEmpty(errMsg)) {
                            errMsg = "位置无法正常解析";
                        } else {
                            errMsg += ",位置无法正常解析";
                        }
                        flag = false;
                    }
                    if (!flag) {
                        throw new IllegalArgumentException(errMsg);
                    }
                } catch (Exception e) {
                    LOGGER.error("ImportServiceImpl.importOrder... dn:" + entry.getKey(), e);
                    if (StringUtils.isEmpty(entry.getValue().getString("执行信息"))) {
                        entry.getValue().put("导入结果", "失败");
                        entry.getValue().put("执行信息", e.getMessage());
                        errRetList.add((JSONObject) entry.getValue());
                    } else {
                        if (entry.getValue().getString("执行信息").indexOf(e.getMessage()) == -1) {
                            entry.getValue().put("执行信息", entry.getValue().getString("执行信息") + "," + e.getMessage());
                        }
                    }
                    fatalErrCanNotImportDNList.add(entry.getKey());
                }
            }
        }
        for (String dn : fatalErrCanNotImportDNList) {
            needImportDNGrouped.remove(dn);
        }

        // 因为数据库查询出来的数据更全所以还是使用map存
        Map<String, OrderOtd> orderOtdMap = new HashMap<>();

        for (int i = 0; i < arrayRows.size(); i++) {
            try {
                OrderOtdDetail orderOtdDetail = new OrderOtdDetail();
                orderOtdDetail.setIsmanual(1);
                if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("ＤＮ"))) {
                    throw new IllegalArgumentException("ＤＮ为空");
                }
                if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("底盘号"))) {
                    throw new IllegalArgumentException("底盘号为空");
                }
                if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("承运车牌"))) {
                    throw new IllegalArgumentException("承运车牌为空");
                }
                if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("定位位置"))) {
                    throw new IllegalArgumentException("定位位置为空");
                }
                if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("定位时间"))) {
                    throw new IllegalArgumentException("定位时间为空");
                }
                String dn = arrayRows.getJSONObject(i).getString("ＤＮ").trim();

                if (needImportDNGrouped.containsKey(dn)) {
                    OrderOtd orderOtd = checkOrderOtd(dn, orderOtdMap);
                    if (ObjectUtils.isEmpty(orderOtd)) {
                        throw new IllegalArgumentException("无此单号");
                    }
                    Date locationTime = formatCellValue2Date(arrayRows.getJSONObject(i).getString("定位时间").trim(),
                            "定位时间");
                    String orderNo = arrayRows.getJSONObject(i).getString("ＤＮ").trim();
                    String location = arrayRows.getJSONObject(i).getString("定位位置").trim();
                    String license = arrayRows.getJSONObject(i).getString("承运车牌").trim();

                    // 系统订单号
                    orderOtdDetail.setSysOrderNo(orderNo);
                    // 定位时间
                    orderOtdDetail.setTrackTime(locationTime);
                    // 地址验证
                    Map<String, String> geoPoint = checkAddress(location, addressMap);
                    // 正常情况百度api解析成功返回
                    if (null != geoPoint && !CollectionUtils.isEmpty(geoPoint)
                            && !StringUtils.isEmpty(geoPoint.get("lat"))) {
                        addressMap.put(location, geoPoint);
                        orderOtdDetail.setLatitude(new BigDecimal(geoPoint.get("lat")));
                        orderOtdDetail.setLongitude(new BigDecimal(geoPoint.get("lng")));
                        orderOtdDetail.setProvince(geoPoint.get("province"));
                        orderOtdDetail.setCity(geoPoint.get("city"));
                        orderOtdDetail.setArea(geoPoint.get("district"));
                        orderOtdDetail.setAddress(location);
                        Map<String, Double> lastLocationMap = new HashMap<String, Double>();
                        lastLocationMap.put("lat", new Double(geoPoint.get("lat")));
                        lastLocationMap.put("lng", new Double(geoPoint.get("lng")));

                        String destAddr = orderOtd.getdProvince() + orderOtd.getdCity();
                        Double remainDistanceInKM = 0.00;
                        Map<String, Double> orderEndMap = new HashMap<String, Double>();
                        Map<String, String> orderEndPoint = checkAddress(destAddr, addressMap);
                        if (null != orderEndPoint && !CollectionUtils.isEmpty(orderEndPoint)
                                && !StringUtils.isEmpty(orderEndPoint.get("lat"))) {
                            addressMap.put(destAddr, orderEndPoint);
                            orderEndMap.put("lat", new Double(orderEndPoint.get("lat")));
                            orderEndMap.put("lng", new Double(orderEndPoint.get("lng")));
                            remainDistanceInKM = BaiDuMapRouteUtil.getDistance(lastLocationMap, orderEndMap) / 1000;
                        } else {
                            remainDistanceInKM = 0.00;
                        }
                        orderOtdDetail.setDistance(remainDistanceInKM.floatValue());
                    } else {
                        throw new IllegalArgumentException("位置无法正常解析");
                    }

                    EntityWrapper<OrderOtdDetail> otdDetailEntity = new EntityWrapper<>();
                    otdDetailEntity.eq("sys_order_no", dn).eq("track_time", locationTime).eq("address", location);
                    List<OrderOtdDetail> otdDetails = orderOtdDetailService.selectList(otdDetailEntity);
                    if (CollectionUtils.isEmpty(otdDetails)) {
                        orderOtdDetailService.insert(orderOtdDetail);
                        // 删除该定位时间冲突的在途明细
                        otdDetailEntity = new EntityWrapper<>();
                        otdDetailEntity.eq("sys_order_no", dn).gt("track_time", locationTime).gt("distance",
                                orderOtdDetail.getDistance());
                        orderOtdDetailService.delete(otdDetailEntity);
                    } else {
                        // 当有相同订单位置和时间不做插入
                    }
                    // 如果是最后一条记录
                    Date lastDate = formatCellValue2Date(needImportDNGrouped.get(dn).getString("定位时间").trim(), "定位时间");
                    if (lastDate.getTime() == locationTime.getTime()) {
                        // orderOtd车牌号不为空 更新车牌号
                        if (!StringUtils.isEmpty(orderOtd.getLicensePlate())) {
                            orderOtd.setLicensePlate(license);
                        }
                        String isDelivery = arrayRows.getJSONObject(i).getString("是否运抵");
                        if (!StringUtils.isEmpty(isDelivery) && isDelivery.trim().equalsIgnoreCase("是")) {
                            orderOtd.setShiptoTime(locationTime);
                        }
                        orderOtdService.updateById(orderOtd);
                        updateNewestPositionRelInfo(dn);
                    }
                    rows_successed++;
                }
            } catch (Exception e) {
                LOGGER.error("ImportServiceImpl.importOrder ...row(" + i + "): ", e);
                if (StringUtils.isEmpty(arrayRows.getJSONObject(i).getString("执行信息"))) {
                    arrayRows.getJSONObject(i).put("导入结果", "失败");
                    arrayRows.getJSONObject(i).put("执行信息", e.getMessage());
                    JSONObject errRow = (JSONObject) arrayRows.getJSONObject(i);
                    errRetList.add(errRow);
                } else {
                    if (arrayRows.getJSONObject(i).getString("执行信息").indexOf(e.getMessage()) == -1) {
                        arrayRows.getJSONObject(i).put("执行信息",
                                arrayRows.getJSONObject(i).getString("执行信息") + "," + e.getMessage());
                    }
                }
            }
        }

        // 只反馈导入异常数据到前端
        result = JSONArray.toJSONString(errRetList);

        Map<String, String> map = new HashMap<>();
        map.put("header", JSONArray.toJSONString(arrayHeader));
        map.put("rows", result);
        map.put("rows_err", errRetList.size() + "");
        map.put("rows_successed", rows_successed + "");

        return map;
    }

    // 从已有的addressMap中查询 有的话就不需要在此调用百度api
    private Map<String, String> checkAddress(String address, Map<String, Map<String, String>> addressMap) {
        for (Map.Entry<String, Map<String, String>> entry : addressMap.entrySet()) {
            if (address.equals(entry.getKey())) {
                return entry.getValue();
            }
        }
        Map<String, String> geoPoint = BaiDuMapGeocodeUtil.addressToGEOPoint(address);
        addressMap.put(address, geoPoint);
        return geoPoint;
    }

    // 从已有orderOtdMap查询 节省查询数据库时间,否则从DB查询
    private OrderOtd checkOrderOtd(String orderNo, Map<String, OrderOtd> orderOtdMap) {
        for (Map.Entry<String, OrderOtd> entry : orderOtdMap.entrySet()) {
            if (entry.getKey().equals(orderNo)) {
                return entry.getValue();
            }
        }
        OrderOtd orderOtd = orderOtdService.selectOne(new EntityWrapper<OrderOtd>().eq("sys_order_no", orderNo));
        orderOtdMap.put(orderNo, orderOtd);
        return orderOtd;
    }

    /**
     * 从传入最新位置计算剩余距离并返回轨迹明细
     *
     * @param orderOtd
     * @return OrderOtdDetail
     */
    public OrderOtdDetail calcOtdDetailFromNewestLocate(OrderOtd orderOtd) {

        OrderOtdDetail orderOtdDetail = new OrderOtdDetail();
        orderOtdDetail.setHeadId(orderOtd.getId());
        orderOtdDetail.setSysOrderNo(orderOtd.getSysOrderNo());
        orderOtdDetail.setTrackTime(orderOtd.getNewestTime());
        orderOtdDetail.setAddress(orderOtd.getNewestPosition());

        // 获取所在地经纬度
        Map<String, Double> latlonMap = addressToGPS(orderOtd.getNewestPosition());
        if (!StringUtils.isEmpty(latlonMap.get("lng")) && !StringUtils.isEmpty(latlonMap.get("lat"))) {
            orderOtdDetail.setLongitude(new BigDecimal(Double.valueOf(Double.valueOf(latlonMap.get("lng")))));
            orderOtdDetail.setLatitude(new BigDecimal(Double.valueOf(Double.valueOf(latlonMap.get("lat")))));

            // 获取剩余距离
            String endAddress = orderOtd.getdProvince() + orderOtd.getdCity() + orderOtd.getdAddress();
            Double remainDistanceInKM = BaiDuMapRouteUtil.getDistance(latlonMap, endAddress) / 1000;
            orderOtdDetail.setDistance(remainDistanceInKM.floatValue());
        } else {
            orderOtdDetail.setLongitude(null);
            orderOtdDetail.setLatitude(null);

            orderOtdDetail.setDistance(0f);
        }
        return orderOtdDetail;
    }

    /**
     * 判断最新位置是否有效
     *
     * @param orderOtd
     * @return
     */
    public boolean isValidNewestLocate(OrderOtd orderOtd) {
        if (orderOtd.getNewestTime() != null && !StringUtils.isEmpty(orderOtd.getNewestPosition())
                && !StringUtils.isEmpty(orderOtd.getNewestPosition().replaceAll("null", ""))) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 判断同单号是否存在同样定位时间的轨迹明细
     *
     * @param orderOtd
     * @return
     */
    public boolean isExistsSameTimeLocate(OrderOtd orderOtd) {
        Wrapper<OrderOtdDetail> detailWrapper = new EntityWrapper<>();
        detailWrapper.eq("sys_order_no", orderOtd.getSysOrderNo());
        detailWrapper.eq("track_time", orderOtd.getNewestTime());
        List<OrderOtdDetail> details = orderOtdDetailService.selectList(detailWrapper);
        if (CollectionUtils.isEmpty(details)) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 删除与导入轨迹冲突的轨迹明细
     *
     * @param newDetail
     */
    private void deleteConflictOtdDetail(OrderOtdDetail newDetail) {
        SimpleDateFormat timeFormatHyphenSiEnd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        OrderOtdDetail updateDetail = new OrderOtdDetail();
        updateDetail.setIsdelete(OrderDetailDeleteFlagEnum.DELETE.getCode());
        Wrapper<OrderOtdDetail> wrapper = new EntityWrapper<>();
        wrapper.eq("sys_order_no", newDetail.getSysOrderNo());
        wrapper.eq("ismanual", OrderDetailIsmanualEnum.NO.getCode());
        wrapper.gt("track_time", timeFormatHyphenSiEnd.format(newDetail.getTrackTime()));
        wrapper.gt("distance", newDetail.getDistance());
        wrapper.eq("isdelete", OrderDetailDeleteFlagEnum.NORMAL.getCode());
        orderOtdDetailService.update(updateDetail, wrapper);
    }

    /**
     * 插入或更新订单流程信息
     *
     * @param orderOtd
     */
    private void insertOrUpdateOtd(OrderOtd orderOtd) {
        EntityWrapper<OrderOtd> ew = new EntityWrapper<>();
        ew.eq("sys_order_no", orderOtd.getSysOrderNo());
        List<OrderOtd> orderOtdList = orderOtdService.selectList(ew);
        if (CollectionUtils.isEmpty(orderOtdList)) {
            // 插入在途表
            orderOtd.setGmtCreate(new Date());
            orderOtdService.insert(orderOtd);
        } else {
            // 更新在途表
            orderOtd.setId(orderOtdList.get(0).getId());
            orderOtd.setGmtModified(new Date());
            orderOtdService.importUpdate(orderOtd);
        }
    }

    private static Date formatString2Date(String dateCellVal, String cellName) throws IllegalArgumentException {
        Assert.notNull(dateCellVal, "日期单元格不能为空");
        Date datePhase = null;
        SimpleDateFormat timeFormatHyphenDEnd = new SimpleDateFormat("yyyy-MM-dd");
        timeFormatHyphenDEnd.setLenient(false);
        SimpleDateFormat timeFormatHyphenSiEnd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        timeFormatHyphenSiEnd.setLenient(false);

        SimpleDateFormat timeFormatSlashDLeadMiEnd = new SimpleDateFormat("dd/MM/yy HH:mm");
        timeFormatSlashDLeadMiEnd.setLenient(false);

        SimpleDateFormat timeFormatSlashDLeadScEnd = new SimpleDateFormat("dd/MM/yy HH:mm:ss");
        timeFormatSlashDLeadScEnd.setLenient(false);

        SimpleDateFormat timeFormatSlashYLeadMiEnd = new SimpleDateFormat("yyyy/MM/dd HH:mm");
        timeFormatSlashYLeadMiEnd.setLenient(false);

        SimpleDateFormat timeFormatSlashYLeadScEnd = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        timeFormatSlashYLeadScEnd.setLenient(false);

        if (null == datePhase) {
            try {
                datePhase = timeFormatHyphenSiEnd.parse(dateCellVal);
                return datePhase;
            } catch (ParseException pe) {
                datePhase = null;
            }
        }
        if (null == datePhase) {
            try {
                datePhase = timeFormatHyphenDEnd.parse(dateCellVal);
                return datePhase;
            } catch (ParseException pe) {
                datePhase = null;
            }
        }
        if (null == datePhase) {
            try {
                datePhase = timeFormatSlashDLeadMiEnd.parse(dateCellVal);
                return datePhase;
            } catch (ParseException pe) {
                datePhase = null;
            }
        }
        if (null == datePhase) {
            try {
                datePhase = timeFormatSlashDLeadScEnd.parse(dateCellVal);
                return datePhase;
            } catch (ParseException pe) {
                datePhase = null;
            }
        }
        if (null == datePhase) {
            try {
                datePhase = timeFormatSlashYLeadMiEnd.parse(dateCellVal);
                return datePhase;
            } catch (ParseException pe) {
                datePhase = null;
            }
        }
        if (null == datePhase) {
            try {
                datePhase = timeFormatSlashYLeadScEnd.parse(dateCellVal);
                return datePhase;
            } catch (ParseException pe) {
                datePhase = null;
            }
        }

        throw new IllegalArgumentException("无效的" + cellName + "日期单元格数据" + dateCellVal);
    }

    private static String testDateFormat(String dateCellVal) {
        Assert.notNull(dateCellVal, "日期单元格不能为空");
        Pattern patternDigtalDate = Pattern.compile("^(\\d+)(\\.\\d*)?$");
        Matcher matcher = patternDigtalDate.matcher(dateCellVal.trim());

        boolean b = matcher.matches();

        if (!b) {
            Pattern patternStringDate = Pattern
                    .compile("^\\d{2,4}[-/]\\d{1,2}[-/]\\d{1,2}\\s*(\\d{1,2}\\:\\d{1,2}(\\:\\d{1,2})?)?$");
            b = patternStringDate.matcher(dateCellVal).matches();

            if (b) {
                return STRING_DATE_FORMAT;
            } else {
                return NOT_DATE_FORMAT;
            }
        } else {
            if (matcher.group(1).length() < matcher.group(0).length()) {
                return NUMBER_DAYS_FORMAT_WITH_CLOCK;
            } else {
                if (matcher.group(1).length() < 6) {
                    return NUMBER_DAYS_FORMAT_ONLY_DATE;
                } else {
                    return NUMBER_MILLISECOND_FORMAT;
                }
            }
        }
    }

    private static Date formatCellValue2Date(String dateCellVal, String cellName) throws IllegalArgumentException {
        Date ret = null;
        String dateFormat = testDateFormat(dateCellVal);
        switch (dateFormat) {
        case NUMBER_DAYS_FORMAT_WITH_CLOCK:
            ret = formatDaysDateWithClock(dateCellVal, cellName);
            break;
        case NUMBER_DAYS_FORMAT_ONLY_DATE:
            ret = formatDaysDateOnlyDate(dateCellVal, cellName);
            break;
        case NUMBER_MILLISECOND_FORMAT:
            ret = formatMillsSecondsDate(dateCellVal, cellName);
            break;
        case STRING_DATE_FORMAT:
            ret = formatString2Date(dateCellVal, cellName);
            break;
        case NOT_DATE_FORMAT:
            throw new IllegalArgumentException("无效的" + cellName + "日期单元格数据" + dateCellVal);
        default:
            throw new IllegalArgumentException("无效的" + cellName + "日期单元格数据" + dateCellVal);
        }
        return ret;
    }

    private static Date formatDaysDateOnlyDate(String dateCellVal, String cellName) {
        Assert.notNull(dateCellVal, cellName + "日期单元格不能为空");
        Pattern patternDigtalDate = Pattern.compile("^(\\d+)(\\.\\d*)?$");
        Matcher matcher = patternDigtalDate.matcher(dateCellVal.trim());

        boolean b = matcher.matches();
        if (b) {
            int days = Integer.parseInt(matcher.group(1));
            Calendar cal = Calendar.getInstance();
            cal.setTimeZone(TimeZone.getTimeZone("UTC+8"));
            cal.setTimeInMillis(0);
            cal.add(Calendar.DAY_OF_YEAR, days);
            cal.add(Calendar.YEAR, -70);// 1900开始和1970开始的区别
            return cal.getTime();
        } else {
            throw new IllegalArgumentException("无效的" + cellName + "日期单元格数据" + dateCellVal);
        }
    }

    private static Date formatDaysDateWithClock(String dateCellVal, String cellName) {
        Assert.notNull(dateCellVal, cellName + "日期单元格不能为空");
        Pattern patternDigtalDate = Pattern.compile("^(\\d+)(\\.\\d*)?$");
        Matcher matcher = patternDigtalDate.matcher(dateCellVal.trim());

        boolean b = matcher.matches();
        if (b) {
            int days = Integer.parseInt(matcher.group(1));
            double clock_in_days = Double.valueOf(matcher.group(2));
            Calendar cal = Calendar.getInstance();
            cal.setTimeZone(TimeZone.getTimeZone("UTC+8"));
            cal.setTimeInMillis(0);
            cal.add(Calendar.DAY_OF_YEAR, days);
            cal.add(Calendar.YEAR, -70);// 1900开始和1970开始的区别
            cal.add(Calendar.MILLISECOND, Double.valueOf(MILLISECOND_OF_DAY * clock_in_days).intValue());
            return cal.getTime();
        } else {
            throw new IllegalArgumentException("无效的" + cellName + "日期单元格数据" + dateCellVal);
        }
    }

    private static Date formatMillsSecondsDate(String dateCellVal, String cellName) {
        Assert.notNull(dateCellVal, cellName + "日期单元格不能为空");
        return new Date(Long.parseLong(dateCellVal.trim()));
    }

    /**
     * 解析地址
     *
     * @param address
     * @return
     */
    public static List<Map<String, String>> addressResolution(String address) {
        String regex = "(?<province>[^省]+自治区|.*?省|.*?行政区|.*?市)(?<city>[^市]+自治州|.*?地区|.*?行政单位|.+盟|市辖区|.*?市|.*?县)(?<county>[^县]+县|.+区|.+市|.+旗|.+海域|.+岛)?(?<town>[^区]+区|.+镇)?(?<orther>.*)";
        Matcher m = Pattern.compile(regex).matcher(address);
        String province = null, city = null, county = null, town = null, orther = null;
        List<Map<String, String>> table = new ArrayList<Map<String, String>>();
        Map<String, String> row = null;
        while (m.find()) {
            row = new LinkedHashMap<String, String>();
            province = m.group("province");
            row.put("province", province == null ? "" : province.trim());
            city = m.group("city");
            row.put("city", city == null ? "" : city.trim());
            county = m.group("county");
            row.put("county", county == null ? "" : county.trim());
            town = m.group("town");
            row.put("town", town == null ? "" : town.trim());
            orther = m.group("orther");
            row.put("orther", orther == null ? "" : orther.trim());
            table.add(row);
        }

        return table;
    }

    /**
     * 返回当天日期时间
     * 
     * @return
     */
    private Date getTodayDate() {
        Calendar calToday = Calendar.getInstance();
        Date now = new Date();
        calToday.setTime(now);
        int year = calToday.get(Calendar.YEAR);
        int month = calToday.get(Calendar.MONTH);
        int day = calToday.get(Calendar.DAY_OF_MONTH);
        calToday.set(year, month, day);
        return calToday.getTime();
    }

    /**
     * 根据在途后的剩余公里数计算剩余在途小时数取整
     * 
     * @param remainDistance
     * @param transportMode
     * @return
     */
    public int calcRestOnwayHours(double remainDistance, String transportMode) {
        Number limitation;
        if (StringUtils.isEmpty("transportMode")) {
            transportMode = "零公里";
        }
        if (transportMode.lastIndexOf("人送") >= 0) {
            // 人送
            limitation = Math.ceil(remainDistance / 550) * 24;
        } else if (transportMode.lastIndexOf("铁") >= 0) {
            // 铁运
            limitation = Math.ceil(remainDistance / 250) * 24 + (24) * 3;
        } else if (transportMode.lastIndexOf("水") >= 0) {
            // 水运
            limitation = Math.ceil(remainDistance / 185) * 24 + (24) * 3;
        } else {
            limitation = Math.ceil(remainDistance / 550) * 24;
        }
        return limitation.intValue();
    }

    /**
     * 计算预计运抵时间
     * 
     * @param orderOtd
     * @param remainDistanceInKM
     * @return
     */
    public Date getExpectedArrivalTime(OrderOtd orderOtd, double remainDistanceInKM) {
        if (orderOtd == null) {
            return null;
        }
        Date today = getTodayDate();
        // 离昌前
        if (StringUtils.isEmpty(orderOtd.getLeaveTime())) {
            // 未安排运力并未入中联库，预计送达时间为空
            if (StringUtils.isEmpty(orderOtd.getInboundTime())
                    && StringUtils.isEmpty(orderOtd.getArrangeCapacityTime())) {
                return null;
            } else if (!StringUtils.isEmpty(orderOtd.getArrangeCapacityTime())) {
                // 已安排运力，预计送达时间=安排时间+在途时效+流转时间
                Double distance = orderOtd.getDistance().doubleValue();
                Double timeLimitation = 0.00;
                Double circulationTime = 0.00;

                if (orderOtd.getTransportType().lastIndexOf("三位") >= 0
                        || orderOtd.getTransportType().lastIndexOf("四位") >= 0) {
                    // 三位板在途时效
                    timeLimitation = distance / 550;
                    // 三位板流转时间
                    circulationTime = 0.0;
                } else if (orderOtd.getTransportType().lastIndexOf("人送") >= 0) {
                    // 人送在途时效
                    timeLimitation = distance / 550;
                    // 人送流转时间
                    circulationTime = 0.5;
                } else if (orderOtd.getTransportType().lastIndexOf("铁") >= 0) {
                    // 铁运在途时效
                    timeLimitation = distance / 250;
                    // 铁运流转时间
                    circulationTime = 2.0;
                } else if (orderOtd.getTransportType().lastIndexOf("水") >= 0) {
                    // 水运在途时效
                    timeLimitation = distance / 185;
                    // 水运流转时间
                    circulationTime = 2.0;
                } else {
                    // 默认按普通零公里在途时效
                    timeLimitation = distance / 550;
                    // 普通零公里流转时间
                    circulationTime = 1.0;
                }

                Calendar calendar = Calendar.getInstance();
                // 安排运力时间
                calendar.setTime(orderOtd.getArrangeCapacityTime());
                // 加上在途时效
                Number limitation = Math.ceil(timeLimitation) * 24;
                calendar.add(Calendar.HOUR_OF_DAY, limitation.intValue());
                // 加上流转时间
                Number circulation = circulationTime * 24;
                calendar.add(Calendar.HOUR_OF_DAY, circulation.intValue());

                if (calendar.getTime().before(today)) {
                    calendar.setTime(today);
                    calendar.add(Calendar.HOUR_OF_DAY, limitation.intValue());
                    calendar.add(Calendar.HOUR_OF_DAY, circulation.intValue());
                }
                return calendar.getTime();
            } else {
                // 未安排运力则以入库时间推预计离昌时间,然后再推预计运抵时间
                // 预计送达时间=入库时间+预计离昌时间+在途时效+流转时间
                Double distance = orderOtd.getDistance().doubleValue();
                Double timeLimitation = 0.00;
                Double circulationTime = 0.00;
                // 暂时写死预计离昌时间三天
                Double fakeLeaveDays = 3.0;
                // 默认按零公里在途时效
                timeLimitation = distance / 550;
                // 零公里流转时间
                circulationTime = 1.0;

                Calendar calendar = Calendar.getInstance();
                // 安排运力时间
                calendar.setTime(orderOtd.getInboundTime());
                // 加上预计离昌天数
                calendar.add(Calendar.DAY_OF_MONTH, fakeLeaveDays.intValue());
                // 加上在途时效
                Number limitation = Math.ceil(timeLimitation) * 24;
                calendar.add(Calendar.HOUR_OF_DAY, limitation.intValue());
                // 加上流转时间
                Number circulation = circulationTime * 24;
                calendar.add(Calendar.HOUR_OF_DAY, circulation.intValue());

                if (calendar.getTime().before(today)) {
                    calendar.setTime(today);
                    calendar.add(Calendar.HOUR_OF_DAY, limitation.intValue());
                    calendar.add(Calendar.HOUR_OF_DAY, circulation.intValue());
                }
                return calendar.getTime();
            }
        } else { // 离昌后
            // 计算剩余公里数
            Double distance = remainDistanceInKM;
            if (distance == null || distance.compareTo(0d) == 0) {
                distance = 0d;
            }
            int limitation = calcRestOnwayHours(remainDistanceInKM, orderOtd.getTransportType());

            Calendar calendar = Calendar.getInstance();
            if (orderOtd.getNewestTime() == null) {
                calendar.setTime(today);
            } else {
                calendar.setTime(orderOtd.getNewestTime());
            }
            if (limitation == 0) {
                if (!StringUtils.isEmpty(orderOtd.getPlanShiptoTime())) {
                    calendar.setTime(orderOtd.getPlanShiptoTime());
                } else {
                    calendar.setTime(orderOtd.getLeaveTime());
                    calendar.add(Calendar.HOUR_OF_DAY,
                            calcRestOnwayHours(orderOtd.getDistance(), orderOtd.getTransportType()));
                }
            } else {
                calendar.add(Calendar.HOUR_OF_DAY, limitation);
            }

            if (calendar.getTime().before(today)) {
                Date oldPlanShipToTime = calendar.getTime();
                calendar.setTime(today);
                if (limitation == 0) {
                    int hoursInterval = 0;
                    if (!StringUtils.isEmpty(orderOtd.getNewestTime())) {
                        hoursInterval = DateUtils.hoursBetween(orderOtd.getNewestTime(), oldPlanShipToTime);
                    } else {
                        hoursInterval = DateUtils.hoursBetween(orderOtd.getLeaveTime(), oldPlanShipToTime);
                    }
                    calendar.add(Calendar.HOUR_OF_DAY, hoursInterval);
                } else {
                    calendar.add(Calendar.HOUR_OF_DAY, limitation);
                }
            }
            return calendar.getTime();
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void updateNewestPositionRelInfo(String sysOrderNo) {
        OrderOtd orderOtd = orderOtdService.selectOne(new EntityWrapper<OrderOtd>().eq("sys_order_no", sysOrderNo));
        Wrapper<OrderOtdDetail> wrapper = new EntityWrapper<>();
        wrapper.eq("sys_order_no", sysOrderNo);
        wrapper.orderBy("track_time", false);
        List<OrderOtdDetail> onwayDetail = orderOtdDetailService.selectList(wrapper);

        String endAddress = orderOtd.getdProvince() + orderOtd.getdCity();
        double remainKM = 0d;
        if (!StringUtils.isEmpty(orderOtd.getShiptoTime())) {
            orderOtd.setNewestPosition(endAddress);
            orderOtd.setNewestTime(orderOtd.getShiptoTime());
        } else if (!StringUtils.isEmpty(orderOtd.getManualShiptoTime())) {
            orderOtd.setNewestPosition(endAddress);
            orderOtd.setNewestTime(orderOtd.getManualShiptoTime());
        } else if (!CollectionUtils.isEmpty(onwayDetail)) {
            // 获取最新在途
            OrderOtdDetail newestOnway = onwayDetail.get(0);
            if (!StringUtils.isEmpty(newestOnway)) {
                String newestPosition = (StringUtils.isEmpty(newestOnway.getProvince()) ? ""
                        : newestOnway.getProvince() + "-")
                        + (StringUtils.isEmpty(newestOnway.getCity()) ? "" : newestOnway.getCity() + "-")
                        + (StringUtils.isEmpty(newestOnway.getArea()) ? "" : newestOnway.getArea() + "-")
                        + (StringUtils.isEmpty(newestOnway.getAddress()) ? "" : newestOnway.getAddress());
                orderOtd.setNewestPosition(newestPosition);
                orderOtd.setNewestTime(newestOnway.getTrackTime());
                remainKM = newestOnway.getDistance();
            } else {
                remainKM = orderOtd.getDistance();
            }
        } else {
            remainKM = orderOtd.getDistance();
        }

        if (!StringUtils.isEmpty(orderOtd.getShiptoTime())) {
            orderOtd.setPlanShiptoTime(orderOtd.getShiptoTime());
        } else if (!StringUtils.isEmpty(orderOtd.getManualShiptoTime())) {
            orderOtd.setPlanShiptoTime(orderOtd.getManualShiptoTime());
        } else {
            // 计算预计送达时间
            orderOtd.setPlanShiptoTime(getExpectedArrivalTime(orderOtd, remainKM));
        }

        if (StringUtils.isEmpty(orderOtd.getInboundTime()) && StringUtils.isEmpty(orderOtd.getArrangeCapacityTime())) {
            orderOtd.setPlanShiptoTime(null);
        }
        orderOtd.setGmtModified(new Date());
        orderOtdService.updateById(orderOtd);
    }

    public static void main(String... args) {
        // String dateCellVal = "43552.3860532407";
        // System.out.println(formatCellValue2Date(dateCellVal, "1"));
        // String dateCellVal2 = "43552";
        // System.out.println(formatCellValue2Date(dateCellVal2, "2"));
        // String dateCellVal3 = "1553850954999";
        // System.out.println(formatCellValue2Date(dateCellVal3, "3"));
        // String dateCellVal4 = "2019/03/25 09:15:55";
        // System.out.println(formatCellValue2Date(dateCellVal4, "4"));
        // String dateCellVal5 = "springfield";
        // System.out.println(formatCellValue2Date(dateCellVal5, "5"));
        // String dateCellVal6 = "02/26/19 22:58";
        // System.out.println(formatString2Date(dateCellVal6, "6"));
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm");
        Date parse = null;
        try {
            parse = simpleDateFormat.parse("12/26/2019 22:58");
        } catch (ParseException e) {
            e.printStackTrace();
        }
        System.out.println(parse);
        // List<Map<String, String>> maps = addressResolution("江西省南昌市青云谱区象湖罗马一号34栋");
        // System.out.println(maps.get(0).get("province"));

    }
}
